let fs = require('mz/fs');
let path = require('path');
let http = require('http');
let context = require('./context');
let request = require('./request');
let response = require('./response');
let eventEmitter = require('events');
let stream = require('stream');

class Koa extends eventEmitter {
    constructor() {
        super();
        this.context = Object.create(context);
        this.request = Object.create(request);
        this.response = Object.create(response);
        // 所有的中间件
        this.middlewares = [];
    }
    // 中间件注册方法
    use(fn) {
        this.middlewares.push(fn);
    }
    // 创建上下文
    createContext(req, res) {
        let ctx = this.context;

        ctx.request = this.request;
        ctx.req = ctx.request.req = req;

        ctx.response = this.response;
        ctx.res = ctx.response.res = res;

        return ctx
    }
    // 组合方法
    compose(ctx) {
        // 将所有的中间件都包装成已经成功的Promise
        function dispatch(index, middles) {
            // 没有中间件了，返回一个成功的Promise;
            if (index === middles.length) {
                return Promise.resolve();
            }
            let middle = middles[index];
            // 所有next的返回都有要是个promise
            // 中间件已经都执行完了
            return Promise.resolve(middle(ctx, () => dispatch(index + 1, middles)))
        }
        return dispatch(0, this.middlewares)
    }
    // 处理用户请求到来时
    handleRequest(req, res) {
        let ctx = this.createContext(req, res);
        // 默认没有调用ctx.body
        res.statusCode = 404;
        let fn = this.compose(ctx);
        // 这是第一个中间件返回的promise
        fn.then(() => {
            if (!ctx.body) {
                ctx.end('Not Found')
            } else if (ctx.body instanceof stream) {
                ctx.body.pipe(res)
            } else if (typeof ctx.body === 'object') {
                res.setHeader('Content-Type', 'application/josn; charset=utf8')
                ctx.end(JSON.stringify(ctx.body))
            } else {
                res.end(ctx.body)
            }
        }).catch((err) => {
            this.emit('error', err)
        })
    }
    // 启动服务器
    listen(...args) {
        let server = http.createServer(this.handleRequest.bind(this));
        server.listen(...args);
    }
}

module.exports = Koa;